package exerciciojsf.armazenamento;

import java.util.HashMap;
import java.util.Map;

import exerciciojsf.modelo.Anuncio;
import exerciciojsf.modelo.Comentario;
import exerciciojsf.modelo.Usuario;

public class Cadastros {
	// referência para uma única instância - Singleton
	private static Cadastros cadastros;

	/**
	 * Sequence para controlar o identificador dos anúncios (devendo sempre ser
	 * incrementado a cada novo cadastro de anúncio.
	 */
	private Long anuncioSequence = 1L;

	/**
	 * Lista dos usuários na base (são identificados pelo login).
	 */
	private Map<String, Usuario> usuarios = new HashMap<String, Usuario>();
	/**
	 * Lista dos anúncios na base de dados (são identificados pelo ID).
	 */
	private Map<Long, Anuncio> anuncios = new HashMap<Long, Anuncio>();

	private Cadastros() {
		super();
		// Para testes, cadastrar anúncios e usuários
		inicializarUsuariosEAnuncios();
	}

	/**
	 * Método para inicializar alguns anúncios, usuários e comentários para
	 * testes.
	 */
	private void inicializarUsuariosEAnuncios() {
		// incluindo usuário anunciante - login: laurorg senha: 123
		usuarios.put("laurorg", new Usuario("laurorg", "Lauro", "123"));
		// incluindo outro usuário, para velidar que só o dono do anúncio responde os comentários do mesmo.
		usuarios.put("teste", new Usuario("teste", "Teste", "123"));
		// adicionando um anúncio qualquer ao usuário "laurorg".
		anuncios.put(
				1L,
				new Anuncio(
						1L,
						usuarios.get("laurorg"),
						"Notebook Ultra Potente",
						"Um notebook extremamente potente, cheio de vantagens.",
						"Esse notebook é muito bom mesmo, eu usei ele minha vida inteira e não me arrependo. Está em ótimo estado."));
		anuncioSequence++;
		usuarios.get("laurorg").adicionarAnuncio(anuncios.get(1L));
		// Adicionando um comentário de uma pessoa qualquer
		anuncios.get(1L).comentar(new Comentario("João", "O notebook roda jogos de última geração?"));
	}

	public static Cadastros getInstance() {
		if (cadastros == null) {
			cadastros = new Cadastros();
		}
		return cadastros;
	}

	/**
	 * Adiciona um novo usuário à base.
	 * 
	 * @param novo
	 *            O novo usuário cadastrado.
	 * @return Retorna verdadeiro caso o usuário seja novo, ou falso caso o
	 *         login já exista na base.
	 */
	public boolean addUsuario(Usuario novo) {
		if (!usuarios.containsKey(novo.getLogin())) {
			usuarios.put(novo.getLogin(), novo);
			return true;
		}
		return false;
	}

	public Usuario getUsuario(String login) {
		return usuarios.get(login);
	}

	/**
	 * Verifica se o usuário que está tentando logar existe e se a senha está
	 * correta
	 * 
	 * @param usuario
	 *            O usuário a ser validado.
	 * @return Retorna verdadeiro caso o usuário exista e a senha esteja
	 *         correta. Caso contrário, retorna falso.
	 */
	public boolean validaUsuario(Usuario usuario) {
		if (usuarios.containsKey(usuario.getLogin())) {
			return usuarios.get(usuario.getLogin()).getSenha()
					.equals(usuario.getSenha());
		} else {
			return false;
		}
	}

	/**
	 * Cadastra um novo anúncio para o usuário logado, acrescentando o
	 * contador/sequence ID dos anúncios.
	 * 
	 * @param usuario
	 *            Usuário que está cadastrando o anúncio.
	 * @param anuncio
	 *            O anúncio a ser salvo.
	 */
	public void cadastrarAnuncio(Usuario usuario, Anuncio anuncio) {
		anuncio.setId(anuncioSequence);
		anuncio.setUsuario(usuario);
		anuncios.put(anuncioSequence, anuncio);
		anuncioSequence++;
		usuario.adicionarAnuncio(anuncio);
	}

	/**
	 * Executa a atualização dos dados de um anúncio baseado em seu ID.
	 * 
	 * @param usuario
	 *            O usuário que está realizando a alteração.
	 * @param anuncio
	 *            O anúncio já atualizado.
	 */
	public void atualizarAnuncio(Usuario usuario, Anuncio anuncio) {
		anuncio.setUsuario(usuario);
		anuncios.put(anuncio.getId(), anuncio);
		usuario.atualizarAnuncio(anuncio);
	}

	public Map<String, Usuario> getUsuarios() {
		return usuarios;
	}

	public Map<Long, Anuncio> getAnuncios() {
		return anuncios;
	}

	/**
	 * Remove um anúncio de um usuário.
	 * 
	 * @param idAnuncio
	 *            O identificador do anúncio a ser removido.
	 * @param usuario
	 *            O usuário responsável pelo anúncio.
	 */
	public void removerAnuncio(Long idAnuncio, Usuario usuario) {
		anuncios.remove(idAnuncio);
		usuario.getAnuncios().remove(idAnuncio);
	}

	/**
	 * Efetua a busca de um anúncio baseado em seu identificador (ID).
	 * 
	 * @param anuncio
	 *            O anúncio desejado.
	 * @return Retorna o anúncio (ou nulo caso não exista).
	 */
	public Anuncio buscarAnuncio(Anuncio anuncio) {
		return anuncios.get(anuncio.getId());
	}

	/**
	 * Busca um comentário de um anúncio baseado em seu identificador.
	 * 
	 * @param idComentario
	 *            O identificador do comentário.
	 * @return Retorna o comntário desejado (ou nulo caso não exista).
	 */
	public Comentario buscarComentario(Long idComentario) {
		for (Anuncio anuncio : anuncios.values()) {
			for (Comentario comentario : anuncio.getComentarios().values()) {
				if (comentario.getId().equals(idComentario)) {
					return comentario;
				}
			}
		}
		return null;
	}

	public Anuncio buscarAnuncioPorComentario(Comentario comentarioDesejado) {
		for (Anuncio anuncio : anuncios.values()) {
			for (Comentario comentario : anuncio.getComentarios().values()) {
				if (comentario.getId().equals(comentarioDesejado.getId())) {
					return anuncio;
				}
			}
		}
		return null;
	}
}